package com.bio.jsf;

import com.bio.jpa.entities.*;
import com.bio.jpa.entities.Session;
import com.bio.jsf.util.JsfUtil;
import com.bio.jpa.session.UserFacade;

import java.io.Serializable;
import java.util.*;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.servlet.http.HttpServletRequest;
import java.util.logging.Logger;
import javax.servlet.http.HttpSession;

@ManagedBean(name = "userController")
@SessionScoped
public class UserController implements Serializable {

    private User current;
    private UserGroup selectedUserGroup;
    private List<User> users;
    private List<UserGroup> canGroupList;
    private List<UserGroup> myGroupList;
    private List<Project> assignedProjects;
    @EJB
    private com.bio.jpa.session.UserFacade ejbFacade;
    private boolean loggedIn;
    private User loggedUser;
    private String context;
    private String lastView;
    private Date lastLogin;
    private Session session;
    private static Logger logger = Logger.getLogger(UserController.class.getName());
    private HashMap<Integer, UserGroup> myGroups = new HashMap<Integer, UserGroup>();

    public List<Project> getAssignedProjects() {
        assignedProjects = getFacade().findAssignedProjects(loggedUser.getUserId());
        return assignedProjects;
    }

    public String getLastView() {
        return lastView;
    }

    public void setLastView(String lastView) {
        this.lastView = lastView;
    }

    public void setAssignedProjects(List<Project> myProjectList) {
        this.assignedProjects = myProjectList;
    }

    public String getLastLogin() {

        if (loggedUser != null) {
            List<Session> sessions = getFacade().sessionInfo(loggedUser.getUserId());
            if (sessions != null && !sessions.isEmpty()) {
                session = sessions.get(0);
                lastLogin = sessions.get(1).getCreationDate();
            }
        }
        if (lastLogin == null) {
            return "Never";
        }
        return lastLogin.toString();
    }

    public UserGroup getSelectedUserGroup() {
        return selectedUserGroup;
    }

    public void setSelectedUserGroup(UserGroup selectedUserGroup) {
        this.selectedUserGroup = selectedUserGroup;
    }

    public void setLastLogin(Date lastLogin) {
        this.lastLogin = lastLogin;
    }

    public String getContext() {
        return context;
    }

    public void setContext(String context) {
        this.context = context;
    }

    public User getLoggedUser() {
        return loggedUser;
    }

    public void setCurrent(User selected) {
        this.current = selected;
    }

    public void setLoggedUser(User loggedUser) {
        this.loggedUser = loggedUser;
    }

    public List<User> getUsers() {
        users = getFacade().findAllLessMe(loggedUser.getUserId());
        return users;
    }

    public List<User> getPendingUsers() {
        users = getFacade().findAll();
        return users;
    }

    public List<UserGroup> getCandidateGroups() {
        canGroupList = getFacade().findGroupsInotIn(current.getUserId());
        return canGroupList;
    }

    public List<UserGroup> getGroups() {
        myGroupList = getFacade().findMyGroups(current.getUserId());
        return myGroupList;
    }

    public List<UserGroup> groupsByUser(User u) {
        myGroupList = getFacade().findMyGroups(u.getUserId());
        return myGroupList;
    }

    public List<UserGroup> getGroupsById(int id) {
        myGroupList = getFacade().findMyGroups(id);
        return myGroupList;
    }

    public User getUserById(int id) {
        return getFacade().find(id);
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }

    public boolean isLoggedIn() {
        return loggedIn;
    }

    public void setLoggedIn(boolean loggedIn) {
        this.loggedIn = loggedIn;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
    private String username = "admin";
    private String password = "admin";

    public UserController() {
    }

    public User getCurrent() {
        return current;
    }

    private UserFacade getFacade() {
        return ejbFacade;
    }

    public String prepareList() {
        resetLists();
        return "List";
    }

    public String prepareView() {
        if (current == null) {
            JsfUtil.addErrorMessage("No User selected");
            return "List";
        }
        return "View";
    }

    public String prepareCreate() {
        current = new User();
        current.setUserCreation(new Date());
        return "Create";
    }

    public void resetLists() {
        users = null;
        selectedUserGroup = null;
        assignedProjects = null;
        myGroupList = null;
        canGroupList = null;
    }

    public String create() {
        try {
            getFacade().create(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("UserCreated"));
            resetLists();
            return "View";
        } catch (Exception e) {
            e.printStackTrace();
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    public boolean isMyselftEditing() {
        logger.info("Checking who are editing");
        if (current == null) {
            current = loggedUser;
        }
        if (current.getUserLogin().equalsIgnoreCase(loggedUser.getUserLogin())) {
            return true;
        }
        return false;
    }

    public String addMeToGroup() {
        System.out.println("Adding User " + current.getUserLogin() + " " + current.getUserId() + " to group " + selectedUserGroup.getGrDesc());
        if (selectedUserGroup == null) {
            JsfUtil.addErrorMessage("User not selected");
        } else {
            UserHasGroup map = new UserHasGroup(new UserHasGroupPK(current.getUserId(), selectedUserGroup.getGrId()));
            map.setUser(current);
            map.setUserGroup(selectedUserGroup);
            current.getUserHasGroupCollection().add(map);

            UserHasGroupController controller = (UserHasGroupController) FacesContext.getCurrentInstance().getApplication().getELResolver().
                    getValue(FacesContext.getCurrentInstance().getELContext(), null, "userHasGroupController");
            controller.setCurrent(map);
            controller.create();

        }
        resetLists();
        return "View";
    }

    public String remMeFromGroup(UserGroup ug) {
        selectedUserGroup = ug;
        System.out.println("Removing user " + current.getUserLogin() + " from group " + selectedUserGroup.getGrDesc());
        if (selectedUserGroup == null) {
            JsfUtil.addErrorMessage("User Group not selected");

        } else {
            UserHasGroup map = new UserHasGroup(new UserHasGroupPK(current.getUserId(), selectedUserGroup.getGrId()));
            map.setUser(current);
            map.setUserGroup(selectedUserGroup);
            System.out.println(map);
            System.out.println(current.getUserHasGroupCollection());
            int i = current.getUserHasGroupCollection().indexOf(map);
            UserHasGroupController controller = (UserHasGroupController) FacesContext.getCurrentInstance().getApplication().getELResolver().
                    getValue(FacesContext.getCurrentInstance().getELContext(), null, "userHasGroupController");

            controller.setCurrent(map);
            controller.justDestroy();
            try {
                current.getUserHasGroupCollection().remove(i);
            } catch (Exception e) {
                JsfUtil.addErrorMessage("Group not found, please try again later");
            }
        }
        resetLists();
        return "View";
    }

    public String remMeFromProject(Project ug) {
        ProjectHasUser map = new ProjectHasUser(new ProjectHasUserPK(ug.getPrjId(), loggedUser.getUserId()));
        assignedProjects.remove(map);
        System.out.println("Removing user " + loggedUser.getUserLogin() + " from Project " + ug.getPrjName());
        if (ug == null) {
            JsfUtil.addErrorMessage("Project not selected");

        } else {

            map.setUser(loggedUser);
            map.setProject(ug);
            System.out.println(map);
            System.out.println(loggedUser.getProjectHasUserCollection());
            try {
                ProjectHasUserController controller = (ProjectHasUserController) FacesContext.getCurrentInstance().getApplication().getELResolver().
                        getValue(FacesContext.getCurrentInstance().getELContext(), null, "projectHasUserController");

                controller.setCurrent(map);
                controller.destroy();
            } catch (Exception e) {
                JsfUtil.addErrorMessage("Project not found, please try again later");
            }
        }
        resetLists();
        return "View";
    }

    public String prepareEdit() {
        return "Edit";
    }

    public String update() {
        try {
            System.out.println(current.getUserLive());
            current.setUserCreation(new Date());
            getFacade().edit(current);
            resetLists();
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("UserUpdated"));
            return "View";
        } catch (Exception e) {
            e.printStackTrace();
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    public String destroy() {
        if (current != null) {
            performDestroy();
            resetLists();
        }

        return "List";
    }

    public String blockUser() {
        if (current != null) {
            current.setUserLive(false);
            update();
            resetLists();
        }

        return "List";
    }

    public String activeUser() {
        if (current != null) {
            current.setUserLive(true);
            update();
            resetLists();
        }

        return "List";
    }

    public String destroyAndView() {
        performDestroy();
        resetLists();
        return "List";
    }

    public String prepareSignUp() {
        resetLists();
        current = new User();
        current.setUserCreation(new Date());
        return "SignUp";
    }

    public void validate() {
        if (getFacade().canCreateLogin(current.getUserLogin())) {
            JsfUtil.addSuccessMessage("login " + current.getUserLogin() + " is available");
        } else {
            JsfUtil.addErrorMessage("Validation:", "There is already an user with login " + current.getUserLogin());
        }
    }

    public String signup() {
        getFacade().create(current);
        JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("UserCreated"));
        loggedUser = current;
        return "index";
    }

    private void performDestroy() {
        try {
            getFacade().remove(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("UserDeleted"));
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, "User cannot be deleted as already has events on system, if you want to avoid user access please deactivte the user");
        }
    }

    public boolean allowedGroups(String groups) {
        if (loggedUser != null) {
            if (loggedUser.getUserId().equals(1)) {
                return true;
            }
        }

        String group[] = new String[]{groups};
        if (groups.contains(",")) {
            group = groups.split(",");
        }
        System.out.println("groups " + myGroups);
        for (int i = 0; i < group.length; i++) {
            System.out.println("Checking " + group[i]);
            if (myGroups.containsKey(Integer.valueOf(group[i]))) {
                System.out.println(myGroups.get(Integer.valueOf(group[i])).getGrDesc() + " allowed");
                return true;
            }
        }
        return false;
    }

    public String login() {
        FacesContext context = FacesContext.getCurrentInstance();
        HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
        setContext(request.getContextPath());
        HttpSession http_ses = request.getSession(true);
        User u = null;
        u = getFacade().auth(username, password);
        myGroups.clear();
        if (u == null) {
            setLoggedIn(false);
            setLoggedUser(null);
            JsfUtil.addErrorMessage("InvalidCredentials");
        } else {
            if (u.getUserLive()) {
                setLoggedIn(true);
                setLoggedUser(u);
                Iterator<UserGroup> it = getGroupsById(getLoggedUser().getUserId()).iterator();
                while (it.hasNext()) {
                    UserGroup ug = it.next();
                    myGroups.put(ug.getGrId(), ug);
                }

                JsfUtil.addSuccessMessage(
                        "Welcome " + u.getUserLogin());
                http_ses.setAttribute("user", u);
                return "index";
            } else {
                JsfUtil.addErrorMessage("User is not Active");
            }
        }
        return null;

    }

    public String prepareViewProfile() {
        setCurrent(getLoggedUser());
        return "/user/Edit";
    }

    public String logout() {
        FacesContext context = FacesContext.getCurrentInstance();
        HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
        setContext(request.getContextPath());
        HttpSession http_ses = request.getSession(true);
        http_ses.invalidate();
        myGroups.clear();
        if (session != null) {
            session.setEndDate(new Date());
            getFacade().logout(session);
        }
        setLoggedIn(false);
        setLoggedUser(null);
        return "login";
    }

    public String expire() {
        setLoggedIn(false);
        return "login";


    }

    @FacesConverter(forClass = User.class)
    public static class UserControllerConverter implements Converter {

        public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
            if (value == null || value.length() == 0) {
                return null;
            }
            UserController controller = (UserController) facesContext.getApplication().getELResolver().
                    getValue(facesContext.getELContext(), null, "userController");
            return controller.ejbFacade.find(getKey(value));
        }

        java.lang.Integer getKey(String value) {
            java.lang.Integer key;
            key = Integer.valueOf(value);
            return key;
        }

        String getStringKey(java.lang.Integer value) {
            StringBuffer sb = new StringBuffer();
            sb.append(value);
            return sb.toString();
        }

        public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
            if (object == null) {
                return null;
            }
            if (object instanceof User) {
                User o = (User) object;
                return getStringKey(o.getUserId());
            } else {
                throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: " + UserController.class.getName());
            }
        }
    }
}
